package syntax

import (
    "regexp"
    "strings"
)
type Regexp = *regexp.Regexp
func r (pattern string) Regexp { return regexp.MustCompile(`^` + pattern) }


const DefaultRootPartName = "root"
const ReplRootPartName = "repl_root"
const IdentifierPartName = "Name"
var __EscapeMap = map[string] string {
    "_bar":  "|",
}
var __IgnoreTokens = [...] string {
    "Comment",
    "Blank",
    "LF",
}

const LF = `\n`
const Blanks = ` \t\r　`
const Symbols = `\{\}\[\]\(\)\.,:;\&\|\\'"` + "`"
const idEverywhereDisallow = (Symbols + Blanks + LF)
const idHeadDisallow = (`0-9` + idEverywhereDisallow)
const IdentifierRegexp = `[^`+idHeadDisallow +`][^`+idEverywhereDisallow+`]*`

var __Tokens = [...] Token {
    // pragma and comment
    Token { Name: "Doc",      Pattern: r(`///[^`+LF+`]*`) },
    Token { Name: "Comment",  Pattern: r(`//[^`+LF+`]*`) },
    Token { Name: "Comment",  Pattern: r(`/\*([^\*/]|\*[^/]|[^\*]/)*\*/`) },
    // blank
    Token { Name: "Blank",  Pattern: r(`[`+Blanks+`]+`) },
    Token { Name: "LF",     Pattern: r(`[`+LF+`]+`) },
    // literals
    Token { Name: "Text",   Pattern: r(`'[^']*'`) },
    Token { Name: "Text",   Pattern: r(`"[^"]*"`) },
    Token { Name: "Int",    Pattern: r(`\-?0[xX][0-9A-Fa-f]+`) },
    Token { Name: "Int",    Pattern: r(`\-?0[oO][0-7]+`) },
    Token { Name: "Int",    Pattern: r(`\-?0[bB][01]+`) },
    Token { Name: "Float",  Pattern: r(`\-?\d+(\.\d+)?[Ee][\+\-]?\d+`) },
    Token { Name: "Float",  Pattern: r(`\-?\d+\.\d+`) },
    Token { Name: "Int",    Pattern: r(`\-?\d+`) },
    Token { Name: "Char",   Pattern: r("`.`") },
    Token { Name: "Char",   Pattern: r(`\\u[0-9A-Fa-f]+`) },
    Token { Name: "Char",   Pattern: r(`\\[a-z]`) },
    // symbols
    Token { Name: "(",    Pattern: r(`\(`) },
    Token { Name: ")",    Pattern: r(`\)`) },
    Token { Name: "[",    Pattern: r(`\[`) },
    Token { Name: "]",    Pattern: r(`\]`) },
    Token { Name: "{",    Pattern: r(`\{`) },
    Token { Name: "}",    Pattern: r(`\}`) },
    Token { Name: "...",  Pattern: r(`\.\.\.`) },
    Token { Name: "..",   Pattern: r(`\.\.`) },
    Token { Name: ".",    Pattern: r(`\.`) },
    Token { Name: ",",    Pattern: r(`\,`) },
    Token { Name: "::",   Pattern: r(`\:\:`) },
    Token { Name: ":=",   Pattern: r(`\:\=`) },
    Token { Name: ":",    Pattern: r(`\:`) },
    Token { Name: ";",    Pattern: r(`\;`) },
    Token { Name: "&",    Pattern: r(`\&`) },
    Token { Name: "|",    Pattern: r(`\|`) },
    Token { Name: `\`,    Pattern: r(`\\`) },
    // keywords
    Token { Name: "If",    Pattern: r(`if`),    Keyword: true },
    Token { Name: "Else",  Pattern: r(`else`),  Keyword: true },
    Token { Name: "When",  Pattern: r(`when`),  Keyword: true },
    Token { Name: "Let",   Pattern: r(`let`),   Keyword: true },
    Token { Name: "New",   Pattern: r(`new`),   Keyword: true },
    // identifier
    Token { Name: "Name",  Pattern: r(IdentifierRegexp) },
}
func GetTokens() ([] Token) { return __Tokens[:] }
func GetIgnoreTokens() ([] string) { return __IgnoreTokens[:] }
func GetIdentifierRegexp() *regexp.Regexp {
    return regexp.MustCompile(IdentifierRegexp)
}

var __ConditionalKeywords = [...] string {
    "@run",
    "@public", "@entry", "@asset", "@type", "@operator",
    "@method", "@const", "@message",
    "@native", "@interface", "@record", "@union",
    "@service", "@data", "@open", "@default",
    "@infix", "@variadic",
    "@singular", "@plural",
    "@=>", "@rec", "@end",
}
func GetKeywordList() ([] string) {
    var list = make([] string, 0)
    for _, v := range __ConditionalKeywords {
        var kw = strings.TrimPrefix(v, "@")
        list = append(list, kw)
    }
    for _, t := range __Tokens {
        if t.Keyword {
            var kw = strings.TrimPrefix(t.Pattern.String(), "^")
            list = append(list, kw)
        }
    }
    return list
}

var __SyntaxDefinition = [...] string {
    "root = stmt*",
      "stmt = decl_entry | decl_type " +
          "| decl_op | decl_method | decl_const | decl_msg",
    "repl_root = repl_assign | repl_run | repl_eval",
      "repl_assign = name := expr!",
      "repl_run = : @run expr!",
      "repl_eval = expr!",
    "decl_entry = @entry block!",
    "decl_type = docs @type name! type_params impl type_def!",
      "type_params? = [ name*, ]!",
        "name = Name",
      "docs? = doc+",
        "doc = Doc",
      "impl? = ( ref_base*, )!",
        "ref_base = module_prefix name",
          "module_prefix? = name :: ",
      "type_def = native_type_def | interface | record | union",
        "native_type_def = @native",
        "interface = service @interface {! method*, }!",
          "service? = @service",
          "method = docs name type!",
        "record = open data @record record_def!",
          "open? = @open",
          "data? = @data",
          "record_def = { field*, }!",
            "field = docs name type! field_default",
            "field_default? = @default (! expr! )!",
        "union = data @union {! union_item*_bar }!",
           "union_item = union_item_def_const | union_item_use_type",
             "union_item_def_const = @const union_const_def+,! ",
               "union_const_def = docs name",
             "union_item_use_type = type",
    "decl_op = docs public @operator infix variadic name! sig! body!",
      "public? = @public",
      "infix? = @infix",
      "variadic? = @variadic",
      "sig = type_params inputs! implicit output!",
        "inputs = record_def",
        "implicit? = inputs",
        "output = type",
      "body = native_body | block!",
        "native_body = @native (! text! )!",
    "decl_method = docs public @method receiver! .! name! type! body!",
      "receiver = name",
    "decl_const = docs public @const name! type! body!",
    "decl_msg = docs public @message msg_lang! name! inputs! msg_expr!",
      "msg_lang = name",
      "msg_expr = msg_expr_sp | msg_expr_plain",
        "msg_expr_sp = msg_singular msg_plural!",
          "msg_singular = @singular (! string! )!",
          "msg_plural = @plural (! string! )!",
        "msg_expr_plain = string",
    "type = ref",
      "ref = ref_base type_args",
        "type_args? = [ type*, ]!",
    "expr = cast* term pipe*",
      "cast = ( [ type! ]! )!",
      "pipe = pipe_call | pipe_ufcs | pipe_cast | pipe_get | pipe_interior",
        "pipe_call = call_ordered | call_unordered",
          "call_ordered = ( expr*, )!",
          "call_unordered = { arg_mapping*, }!",
            "arg_mapping = name arg_mapping_to",
              "arg_mapping_to? = : expr!",
        "pipe_ufcs = _bar ref! pipe_call!",
        "pipe_cast = . cast",
        "pipe_get = . name",
        "pipe_interior = . ( ref_base! )!",
    "term = infix_term | lambda | if | when | block | ref_term " +
        "| char | int | float | string ",
      "infix_term = ( infix_left operator! infix_right! )!",
        "infix_left = expr",
        "operator = ref",
        "infix_right = expr",
      "lambda = { & input_names rec @=>! expr! }!",
        "input_names? = ( name+,! )!",
        "rec? = @rec (! name! )!",
      "if = If (! cond! )! if_yes elif* Else! if_no",
        "cond = expr",
        "if_yes = block!",
        "if_no = block!",
        "elif = Else If (! cond! )! block!",
      "when = When (! expr+,! )! {! branch+,! }!",
        "branch = branch_pattern+_bar input_names @=>! expr!",
          "branch_pattern = Else | pattern",
            "pattern = pattern_single | pattern_multiple",
              "pattern_single = name",
              "pattern_multiple = ( name+,! )!",
      "block = { binding* expr! }!",
        "binding = binding_plain | binding_cps",
          "binding_plain = Let pattern! :=! expr! ,!",
          "binding_cps = \\ ref! cps_binding expr! ,!",
            "cps_binding? = pattern := ",
      "ref_term = new ref",
        "new? = New",
      "char = Char",
      "int = Int",
      "float = Float",
      "string = text string_part* ",
        "text = Text",
        "string_part = .. string_part_content!",
          "string_part_content = text | char | block",
}


